package cn.juque.jdfsystem.handler;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RandomUtil;
import cn.juque.common.base.BaseRequestVO;
import cn.juque.common.base.BaseResponseVO;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.constants.StringConstants;
import cn.juque.common.fastjson.abstracts.AbstractTypeReference;
import cn.juque.common.utils.HttpClientUtil;
import cn.juque.common.utils.dto.PostDTO;
import cn.juque.jdfsystem.config.JdfConfig;
import cn.juque.jdfsystem.contants.BusinessConstants;
import cn.juque.jdfsystem.disruptor.bo.FileAddBodyBO;
import cn.juque.jdfsystem.disruptor.bo.FileChangeBodyBO;
import cn.juque.jdfsystem.enums.ConfigCodeEnum;
import cn.juque.jdfsystem.helper.ConfigInfoHelper;
import cn.juque.jdfsystem.helper.RegisterInfoHelper;
import cn.juque.jdfsystem.vo.message.FileAddParamVO;
import cn.juque.jdfsystem.vo.message.FileChangeParamVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>HttpMessageHandler</li>
 * </ul>
 * @date 2023-01-11 16:25:04
 **/
@Slf4j
@Component("httpMessageHandler")
public class HttpMessageHandler {

    private static final String BASE_URL = "/jdf/message/";

    @Resource
    private RegisterInfoHelper registerInfoHelper;

    @Resource
    private ConfigInfoHelper configInfoHelper;

    @Resource
    private JdfConfig jdfConfig;

    /**
     * 注册信息发生变更
     */
    public void registerChange() {
        String url = BASE_URL + "register/change";
        BaseRequestVO<String> requestVO = new BaseRequestVO<>();
        requestVO.setParam(this.jdfConfig.getNodeName());
        List<BaseResponseVO<Boolean>> list = this.batchSendPost(url, MapUtil.newHashMap(1), requestVO);
        long count = list.stream().filter(f -> !MessageEnum.OK.getCode().equals(f.getCode())).count();
        if (count > 0) {
            log.error("注册信息通知存在{}个节点异常", count);
        }
    }

    /**
     * 配置信息发生变更
     */
    public void configChange() {
        String url = BASE_URL + "config/change";
        BaseRequestVO<String> requestVO = new BaseRequestVO<>();
        requestVO.setParam(this.jdfConfig.getNodeName());
        List<BaseResponseVO<Boolean>> list = this.batchSendPost(url, MapUtil.newHashMap(1), requestVO);
        long count = list.stream().filter(f -> !MessageEnum.OK.getCode().equals(f.getCode())).count();
        if (count > 0) {
            log.error("配置信息通知存在{}个节点异常", count);
        }
    }

    /**
     * 平台信息发生变更
     */
    public void platformChange() {
        String url = BASE_URL + "platform/change";
        BaseRequestVO<String> requestVO = new BaseRequestVO<>();
        requestVO.setParam(this.jdfConfig.getNodeName());
        List<BaseResponseVO<Boolean>> list = this.batchSendPost(url, MapUtil.newHashMap(1), requestVO);
        long count = list.stream().filter(f -> !MessageEnum.OK.getCode().equals(f.getCode())).count();
        if (count > 0) {
            log.error("平台信息通知存在{}个节点异常", count);
        }
    }

    /**
     * 发送新增文件的消息
     *
     * @param bodyBO FileChangeBodyBO
     */
    public void addFile(FileAddBodyBO bodyBO) {
        String url = BASE_URL + "file/add";
        FileAddParamVO paramVO = new FileAddParamVO();
        BeanUtil.copyProperties(bodyBO, paramVO);
        paramVO.setNodeName(this.jdfConfig.getNodeName());
        BaseRequestVO<FileAddParamVO> requestVO = new BaseRequestVO<>();
        requestVO.setParam(paramVO);
        List<BaseResponseVO<Boolean>> list = this.batchSendPost(url, MapUtil.newHashMap(1), requestVO);
        long count = list.stream().filter(f -> !MessageEnum.OK.getCode().equals(f.getCode())).count();
        if (count > 0) {
            log.error("发送新增文件的通知存在{}个节点异常", count);
        }
    }

    /**
     * 发送状态变更的文件
     *
     * @param bodyBO FileChangeBodyBO
     */
    public void fileFlagChange(FileChangeBodyBO bodyBO) {
        String url = BASE_URL + "file/changeFlag";
        FileChangeParamVO paramVO = new FileChangeParamVO();
        BeanUtil.copyProperties(bodyBO, paramVO);
        paramVO.setNodeName(this.jdfConfig.getNodeName());
        BaseRequestVO<FileChangeParamVO> requestVO = new BaseRequestVO<>();
        requestVO.setParam(paramVO);
        List<BaseResponseVO<Boolean>> list = this.batchSendPost(url, MapUtil.newHashMap(1), requestVO);
        long count = list.stream().filter(f -> !MessageEnum.OK.getCode().equals(f.getCode())).count();
        if (count > 0) {
            log.error("文件状态变更通知存在{}个节点异常", count);
        }
    }

    /**
     * 发送需要删除的文件
     *
     * @param list list
     */
    public void deleteFile(List<String> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        String url = BASE_URL + "file/delete";
        BaseRequestVO<List<String>> requestVO = new BaseRequestVO<>();
        requestVO.setParam(list);
        List<BaseResponseVO<Boolean>> responseList = this.batchSendPost(url, MapUtil.newHashMap(1), requestVO);
        long count = responseList.stream().filter(f -> !MessageEnum.OK.getCode().equals(f.getCode())).count();
        if (count > 0) {
            log.error("删除文件通知存在{}个节点异常", count);
        }
    }

    /**
     * 发送心跳数据包
     *
     * @return 异常的ip地址
     */
    public List<String>[] checkHeartbeat() {
        String url = BASE_URL + "register/check";
        List<String> list = this.registerInfoHelper.getAllIp();
        Map<String, String> headers = MapUtil.newHashMap(1);
        headers.put(BusinessConstants.SIGNATURE, this.configInfoHelper.getConfigValue(ConfigCodeEnum.SIGNATURE.getCode()));
        BaseRequestVO<Integer> requestVO = new BaseRequestVO<>();
        Integer code = RandomUtil.randomInt(0, 10);
        requestVO.setParam(code);
        List<String> normalIpList = CollUtil.newArrayList();
        List<String> errorIpList = CollUtil.newArrayList();
        for (String f : list) {
            BaseResponseVO<Integer> responseVO = this.singleSendPost(f + url, headers, requestVO);
            if (MessageEnum.OK.getCode().equals(responseVO.getCode()) && code.equals(responseVO.getData())) {
                normalIpList.add(f);
            } else {
                errorIpList.add(f);
            }
        }
        List<String>[] result = ArrayUtil.newArray(List.class, 2);
        result[0] = normalIpList;
        result[1] = errorIpList;
        return result;
    }

    /**
     * 批量发送
     *
     * @param relativeUrl 相对路径
     * @param headers     请求头
     * @param requestVO   报文
     * @param <T>         泛型
     * @return list
     */
    private <T> List<BaseResponseVO<T>> batchSendPost(String relativeUrl, Map<String, String> headers, BaseRequestVO<?> requestVO) {
        List<String> list = this.registerInfoHelper.getValidOtherIp();
        if (MapUtil.isEmpty(headers)) {
            headers = MapUtil.newHashMap(1);
        }
        headers.put(BusinessConstants.SIGNATURE, this.configInfoHelper.getConfigValue(ConfigCodeEnum.SIGNATURE.getCode()));
        List<BaseResponseVO<T>> responseList = CollUtil.newArrayList();
        for (String f : list) {
            BaseResponseVO<T> responseVO = this.singleSendPost(f + relativeUrl, headers, requestVO);
            if (!MessageEnum.OK.getCode().equals(responseVO.getCode())) {
                log.error("{}请求失败", f + relativeUrl);
            }
            responseList.add(responseVO);
        }
        return responseList;
    }

    /**
     * 发送单个POST请求
     *
     * @param url       url
     * @param headers   请求头
     * @param requestVO 数据包
     * @param <T>       泛型
     * @return BaseResponseVO
     */
    private <T> BaseResponseVO<T> singleSendPost(String url, Map<String, String> headers, BaseRequestVO<?> requestVO) {
        try {
            PostDTO postDTO = new PostDTO(StringConstants.HTTP + url, headers, requestVO, null);
            return HttpClientUtil.post(postDTO, new AbstractTypeReference<BaseResponseVO<T>>() {
            });
        } catch (Exception e) {
            log.error("{} error:{}", url, e.getMessage());
        }
        return new BaseResponseVO<>(MessageEnum.SYSTEM_ERROR, null);
    }
}
